
#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <functional>
#include <sys/wait.h>
#include "Task.hpp"
#include "Channel.hpp"
// 1.我们自己就是master
using namespace std;
using work_t = std::function<void()>;

extern TaskManager tM;
// 约定错误码
enum
{
   OK = 0,
   UsageError,
   PipeError,
   ForkError
};

class ProcessPool
{
public:

   ProcessPool(int n,work_t w)
   :num(n),
   work(w)
      {}
   void DebugPrint()
   {
      for (auto &c : channels)
      {
         cout << c.Name() << endl;
      }
   }

   // channels输出型参数
   // work_t work:回调函数
   int InitPorcessPool()
   {
      for (int i = 0; i < num; i++)
      {
         // 1.创建管道
         int pipefd[2] = {0};
         int n = pipe(pipefd);
         if (n < 0)
            return PipeError; // 管道创建失败
         // 2.管道创建成功，创建子进程
         pid_t id = fork();
         if (id < 0)
            return ForkError; // 创建子进程失败
         if (id == 0)         // child
         {
            ::close(pipefd[1]); // 子进程关闭写
            dup2(pipefd[0], 0);
            work();  // 工作
            exit(0); // 工作做完直接结束只会完成任务
         }
         // father
         ::close(pipefd[0]);
         channels.emplace_back(pipefd[1], id);
      }
      return OK;
   }

   void DispatchTask()
   {
      int who = 0;
      int num = 20;
      while (num--)
      {
         // a.选择一个任务
         int task = tM.SelectTask();
         // b.选择一个子进程/Channel 轮询
         Channel &cur = channels[who++];
         who %= channels.size();
         cout << "#########################" << endl;
         cout << "send " << task << " to " << cur.Name() << ",任务还剩" << num << endl;
         cout << "#########################" << endl;
         // c.派发任务
         cur.Send(task);
         sleep(1);
      }
   }

   void CleanProcessPool()
   {
      for (auto &c : channels)
      {
         c.Close();
      }
      // 回收子进程
      for (auto &c : channels)
      {
         pid_t rid = ::waitpid(c.ID(), nullptr, 0);
         if (rid > 0)
         {
            cout << "child: " << rid << "wait ... success" << endl;
         }
      }
   }

private:
   vector<Channel> channels;
   int num;
   work_t work;
};
